﻿#include "lemp.h"

static int safe_strcmp(char* t1, size_t l1, char* t2, size_t l2)
{

	size_t cmp_len = l1 < l2 ? l1 : l2;
	for (size_t i = 0; i < cmp_len; i++) {
		if (*(t1 + i) != *(t2 + i)) {
			return -1;
		}
	}
	return 0;
}
static int safe_strcpy(char* td, size_t ld, char* ts, size_t ls)
{
	size_t cmp_len = ld < ls ? ld : ls;
	for (size_t i = 0; i < cmp_len; i++) {
		*(td + i) = *(ts + i);
	}
	return 0;
}


// 默认哈希函数
uint32_t lemp_get_hash(char* name, uint8_t len)
{
	len = len != 0 ? len : strlen(name);
	if (len == 0) {
		return -1;
	}
	uint32_t sum = 0;
	for (int i = 0; i < len; i++) {
		sum = name[i];
	}
	return sum;
}



int	lemp_init(lemp_handle_t* hander)
{
	hander->get_hash = lemp_get_hash;
	hander->hash_table_size = HASH_TABLE_SIZE;
	for (int i = 0; i < HASH_TABLE_SIZE; i++) {
		hander->table[i] = NULL;
	}
	return 0;
}


int lemp_event_cb_regester(lemp_handle_t* hander, char* name, uint8_t len, void* cb, lemp_event_times_t times)
{
	lemp_event_t* e = NULL;
	int flag = lemp_find_event(hander, name, len, &e);

	lemp_event_cb_t* e_node = (lemp_event_cb_t*) lemp_malloc(sizeof(lemp_event_cb_t));
	if (e_node == NULL) {
		return -1;
	}
	e_node->next = NULL;

	e_node->callback = cb;
	e_node->times = times;

	if (flag != 0 || e == NULL)	// 不存在事件结点
	{
		// 新建事件结点
		lemp_event_t* event = (lemp_event_t*) lemp_malloc(sizeof(lemp_event_t));
		if (event == NULL) {
			lemp_free(e_node);
			return -2;
		}
		event->next = NULL;
		event->event_nodes = NULL;

		safe_strcpy(event->name, EVENT_NAME_LENGTH, name, len);
		event->name_len = len;
		uint32_t hash_code = hander->get_hash(name, len);
		event->hash_code = hash_code;
		lemp_event_add(hander, hash_code, event);
		e = event;
	}

	lemp_event_cb_t* node_ptr = e->event_nodes;

	if (node_ptr == NULL) {
		e->event_nodes = e_node;
		return 0;
	}

	while (1) {
		if (node_ptr->next == NULL) {
			node_ptr->next = e_node;
			return 0;
		}
		node_ptr = node_ptr->next;
	}


}



static int lemp_event_add(lemp_handle_t* hander, uint32_t hash_code, lemp_event_t* e)
{
	uint8_t index = hash_code % hander->hash_table_size;

	lemp_event_t* event = (lemp_event_t*) hander->table[index];
	if (event == NULL) {
		hander->table[index] = e;
		return 0;
	}

	while (1) {
		if (event->next == NULL) {
			event->next = e;
			return 0;
		}
		event = event->next;
	}
}

int lemp_event_emit(lemp_handle_t* hander, char* name, uint8_t len, void* args)
{
	lemp_event_t* e = NULL;
	int flag = lemp_find_event(hander, name, len, &e);
	if (flag != 0 || e == NULL)	// 不存在结点
	{
		return -1;
	}
	lemp_event_cb_t* node_ptr = e->event_nodes;
	lemp_event_cb_t* node_pre = NULL;
	while (1) {
		if (node_ptr == NULL) {

			//if (args != NULL) {		// 释放参数内存
			//	lemp_free(args);
			//}

			return 0;
		}
		node_ptr->callback(args);		// 调用事件回调


		if (node_ptr->times == LEMP_EVENT_TIMES_ONCE) {		// 一次性事件回调
			if (node_pre != NULL) {		// 不为头结点
				node_pre->next = node_ptr->next;
				node_ptr = node_ptr->next;
				lemp_free(node_ptr);
			}
			else {		// 为头结点
				e->event_nodes = node_ptr->next;
				lemp_free(node_ptr);
				node_ptr = e->event_nodes;
			}
		}
		else
		{
			node_pre = node_ptr;
			node_ptr = node_ptr->next;
		}
	}

}
int lemp_event_cb_delete(lemp_handle_t* hander, char* name, uint8_t len, void* cb)
{
	lemp_event_t* e = NULL;
	int flag = lemp_find_event(hander, name, len, &e);
	if (flag != 0 || e == NULL)	// 不存在事件结点
	{
		return -1;
	}

	lemp_event_cb_t* node_ptr = e->event_nodes;
	lemp_event_cb_t* node_pre = NULL;
	while (1) {
		if (node_ptr == NULL) {
			return -1;
		}

		if (node_ptr->callback == cb) {
			if (node_pre != NULL) {		// 不为头结点
				node_pre->next = node_ptr->next;
				node_ptr = node_ptr->next;
				lemp_free(node_ptr);
				return 0;
			}
			else {		// 为头结点
				e->event_nodes = node_ptr->next;
				lemp_free(node_ptr);
				return 0;
			}
		}
		else {
			node_pre = node_ptr;
			node_ptr = node_ptr->next;
		}

	}

}


static int lemp_find_event(lemp_handle_t* hander, char* name, uint8_t len, lemp_event_t** e)
{

	uint32_t hash_code = hander->get_hash(name, len);

	uint8_t index = hash_code % hander->hash_table_size;

	lemp_event_t* event = (lemp_event_t*) hander->table[index];

	while (1) {
		if (event == NULL) {
			*e = NULL;
			return -1;
		}

		if (event->hash_code == hash_code && event->name_len == len) {
			int flag = safe_strcmp(event->name, event->name_len, name, len);
			if (flag == 0) {
				*e = event;
				return 0;
			}
		}
		event = event->next;
	}
	*e = NULL;
	return -1;
}
